#ifndef __BLACK_VECTOR_H__
#define __BLACK_VECTOR_H__

#include <assert.h>
#include "maths/default.h"
#include "maths/func.h"

namespace black
{
	// Classes :
	class vec3;
	class vec3_128;
	class vec4;
	class vec4_128;

	//***************************************************************
	// Vec3
	//***************************************************************
	/** \class vec3 */
	class vec3
	{
	public:
		bFORCEINLINE vec3			();
		bFORCEINLINE vec3			( float x, float y, float z );
		bFORCEINLINE explicit vec3	( const float fVal[3] );
		bFORCEINLINE explicit vec3	( float fVal );
		bFORCEINLINE vec3			( const vec3& v );

		bFORCEINLINE const vec3&	operator +	() const;
		bFORCEINLINE vec3			operator -	() const;

		bFORCEINLINE vec3			operator +	( const vec3& v ) const;
		bFORCEINLINE vec3			operator -	( const vec3& v ) const;
		bFORCEINLINE vec3			operator *	( float fVal ) const;
		bFORCEINLINE vec3			operator /	( float fVal ) const;

		bFORCEINLINE vec3&			operator =	( float fVal );
		bFORCEINLINE vec3&			operator =	( const vec3& v );
		bFORCEINLINE const vec3&	operator +=	( const vec3& v );
		bFORCEINLINE const vec3&	operator +=	( float fVal );
		bFORCEINLINE const vec3&	operator -=	( const vec3& v );
		bFORCEINLINE const vec3&	operator -=	( float fVal );
		bFORCEINLINE const vec3&	operator *=	( float fVal );
		bFORCEINLINE const vec3&	operator /=	( float fVal );

		bFORCEINLINE float			operator []	( size_t i ) const;
		bFORCEINLINE float&			operator []	( size_t i );

		bFORCEINLINE bool			operator ==	( float fVal ) const;
		bFORCEINLINE bool			operator ==	( const vec3& v ) const;
		bFORCEINLINE bool			operator !=	( float fVal ) const;
		bFORCEINLINE bool			operator !=	( const vec3& v ) const;

		bFORCEINLINE void			set				( float fX, float fY, float fZ );
		bFORCEINLINE void			set				( const vec3& v );
		bFORCEINLINE void			set				( const vec4& v );
		bFORCEINLINE void			setLength		( float fLength );
		bFORCEINLINE float			length			() const;
		bFORCEINLINE float			fastLength		() const;
		bFORCEINLINE float			squaredLength	() const;
		bFORCEINLINE float			distance		( const vec3& v ) const;
		bFORCEINLINE float			squaredDistance	( const vec3& v ) const;
		bFORCEINLINE float			dot				( const vec3& v ) const;
		bFORCEINLINE vec3			cross			( const vec3& v ) const;
		bFORCEINLINE void			cross			( vec3& res, const vec3& v ) const;
		bFORCEINLINE void			normalize		();
		bFORCEINLINE vec3			normalized		() const;
		bFORCEINLINE void			normalizeFast	();
		bFORCEINLINE bool			isEqual			( const vec3& v, float epsilon ) const;
		bFORCEINLINE bool			isEqual			( float fVal, float epsilon ) const;
		bFORCEINLINE void			setZero			();
		bFORCEINLINE bool			isZero			() const;
		bFORCEINLINE bool			isNearZero		() const;
		bFORCEINLINE bool			isUnit			() const;
		bFORCEINLINE bool			isNearUnit		() const;
		bFORCEINLINE void			clamp			( float fMin, float fMax );
		bFORCEINLINE float			angle			( const vec3& v ) const;
		
		bFORCEINLINE void			lerp			( const vec3& v, float fCoef );
		bFORCEINLINE void			nlerp			( const vec3& v, float fCoef );
		void						slerp			( const vec3& v, float fCoef );

		bFORCEINLINE bool			isValid			() const;

		static const vec3 ZERO;
		static const vec3 ONE;
		static const vec3 X_AXIS;
		static const vec3 Y_AXIS;
		static const vec3 Z_AXIS;
		static const vec3 NX_AXIS;
		static const vec3 NY_AXIS;
		static const vec3 NZ_AXIS;

		float x, y, z;
	};

#ifdef bSSE

	//***************************************************************
	// Vec3_128
	//***************************************************************
	/**
	\brief 128 bits vec3 for SIMD optimizations such as SSE.
	Faster than normal vec3 but takes 4 additional bytes for padding */
	class bALIGN16 vec3_128 : public vec3
	{
	public:
		bFORCEINLINE vec3_128			();
		bFORCEINLINE vec3_128			( float x, float y, float z );
		bFORCEINLINE explicit vec3_128	( const float fVal[3] );
		bFORCEINLINE explicit vec3_128	( float fVal );
		bFORCEINLINE vec3_128			( const vec3_128& v );
		bFORCEINLINE vec3_128			( const vec3& v );

		bFORCEINLINE vec3_128&			operator =	( float fVal );
		bFORCEINLINE vec3_128&			operator =	( const vec3& v );
		bFORCEINLINE vec3_128&			operator =	( const vec3_128& v );
		bFORCEINLINE vec3_128&			operator =	( const __m128& v );

		bFORCEINLINE const vec3_128&	operator +=	( const vec3& v );
		bFORCEINLINE const vec3_128&	operator +=	( const vec3_128& v );
		bFORCEINLINE const vec3_128&	operator +=	( float fVal );
		bFORCEINLINE const vec3_128&	operator -=	( const vec3& v );
		bFORCEINLINE const vec3_128&	operator -=	( const vec3_128& v );
		bFORCEINLINE const vec3_128&	operator -=	( float fVal );
		bFORCEINLINE const vec3_128&	operator *=	( float fVal );
		bFORCEINLINE const vec3_128&	operator /=	( float fVal );

		bFORCEINLINE bool			operator ==	( float fVal ) const;
		bFORCEINLINE bool			operator ==	( const vec3& v ) const;
		bFORCEINLINE bool			operator ==	( const vec3_128& v ) const;
		bFORCEINLINE bool			operator !=	( float fVal ) const;
		bFORCEINLINE bool			operator !=	( const vec3& v ) const;
		bFORCEINLINE bool			operator !=	( const vec3_128& v ) const;

		bFORCEINLINE operator __m128&();
		bFORCEINLINE operator const __m128&() const;

		bFORCEINLINE float			length			() const;
		bFORCEINLINE float			squaredLength	() const;
		bFORCEINLINE float			dot				( const vec3_128& v ) const;
		bFORCEINLINE __m128			dot				( const vec3_128 v[4] ) const;
		bFORCEINLINE void			cross			( vec3_128& vRes, const vec3_128& v ) const;
		bFORCEINLINE void			normalize		();
		bFORCEINLINE vec3_128		normalized		() const;
		bFORCEINLINE void			normalizeFast	();
		bFORCEINLINE void			setZero			();

		static const vec3_128 ZERO;
		static const vec3_128 ONE;
		static const vec3_128 X_AXIS;
		static const vec3_128 Y_AXIS;
		static const vec3_128 Z_AXIS;
		static const vec3_128 NX_AXIS;
		static const vec3_128 NY_AXIS;
		static const vec3_128 NZ_AXIS;

		float pad;
	};
#else // NOT bSSE
	typedef vec3 vec3_128;
#endif // bSSE

	//***************************************************************
	// Vec4
	//***************************************************************
	/** \class vec4
	* Do not use this directly, use 'vec4' instead */
	class vec4 : public vec3
	{
	public:
		bFORCEINLINE vec4			();
		bFORCEINLINE vec4			( float x, float y, float z, float w = 1.f );
		bFORCEINLINE explicit vec4	( const float fVal[4] );
		bFORCEINLINE explicit vec4	( float fVal );
		bFORCEINLINE vec4			( const vec4& v );

		bFORCEINLINE const vec4&	operator +	() const;
		bFORCEINLINE vec4			operator -	() const;

		bFORCEINLINE vec4			operator +	( const vec4& v ) const;
		bFORCEINLINE vec4			operator -	( const vec4& v ) const;
		bFORCEINLINE vec4			operator *	( float fVal ) const;
		bFORCEINLINE vec4			operator /	( float fVal ) const;

		bFORCEINLINE vec4&			operator =	( float fVal );
		bFORCEINLINE vec4&			operator =	( const vec4& v );
		bFORCEINLINE const vec4&	operator +=	( const vec4& v );
		bFORCEINLINE const vec4&	operator +=	( float fVal );
		bFORCEINLINE const vec4&	operator -=	( const vec4& v );
		bFORCEINLINE const vec4&	operator -=	( float fVal );
		bFORCEINLINE const vec4&	operator *=	( float fVal );
		bFORCEINLINE const vec4&	operator /=	( float fVal );

		bFORCEINLINE float			operator []	( const size_t i ) const;
		bFORCEINLINE float&			operator []	( const size_t i );

		bFORCEINLINE bool			operator ==	( float fVal ) const;
		bFORCEINLINE bool			operator ==	( const vec4& v ) const;
		bFORCEINLINE bool			operator !=	( float fVal ) const;
		bFORCEINLINE bool			operator !=	( const vec4& v ) const;

		bFORCEINLINE void			set				( float fX, float fY, float fZ, float fW );
		bFORCEINLINE void			set				( const vec3& v );
		bFORCEINLINE void			set				( const vec4& v );
		bFORCEINLINE float			length			() const;
		bFORCEINLINE float			squaredLength	() const;
		bFORCEINLINE float			dot				( const vec4& v ) const;
		bFORCEINLINE vec4			cross			( const vec4& v ) const;
		bFORCEINLINE void			cross			( vec4& res, const vec4& v ) const;
		bFORCEINLINE void			normalize		();
		bFORCEINLINE vec4			normalized		() const;
		bFORCEINLINE void			normalizeFast	();
		bFORCEINLINE bool			isEqual			( float fVal, float epsilon ) const;
		bFORCEINLINE bool			isEqual			( const vec4& v, float epsilon ) const;
		bFORCEINLINE bool			isUnit			() const;
		bFORCEINLINE void			setZero			();

		bFORCEINLINE void			lerp			( const vec4& v, float fCoef );

		bFORCEINLINE bool			isValid			() const;

		static const vec4 ZERO;
		static const vec4 ONE;
		static const vec4 X_AXIS;
		static const vec4 Y_AXIS;
		static const vec4 Z_AXIS;
		static const vec4 NX_AXIS;
		static const vec4 NY_AXIS;
		static const vec4 NZ_AXIS;

		float w;
	};

	//***************************************************************
	// vec4_128
	//***************************************************************
#ifdef bSSE
	class bALIGN16 vec4_128 : public vec4
	{
	public:
		bFORCEINLINE vec4_128			();
		bFORCEINLINE vec4_128			( float x, float y, float z, float w = 1.f );
		bFORCEINLINE explicit vec4_128	( const float fVal[4] );
		bFORCEINLINE explicit vec4_128	( float fVal );
		bFORCEINLINE vec4_128			( const vec4& v );

		bFORCEINLINE operator __m128&();
		bFORCEINLINE operator const __m128&() const;

		static const vec4_128 ZERO;
		static const vec4_128 ONE;
		static const vec4_128 X_AXIS;
		static const vec4_128 Y_AXIS;
		static const vec4_128 Z_AXIS;
		static const vec4_128 NX_AXIS;
		static const vec4_128 NY_AXIS;
		static const vec4_128 NZ_AXIS;
	};
#else // NOT bSSE
	typedef vec4 vec4_128;
#endif // bSSE

	//***************************************************************
	// vec2
	//***************************************************************
	class vec2
	{
	public:
		float x, y;
	};
}

#include "maths/inl/vector.inl"

#endif // __BLACK_VECTOR_H__
//---------------------------------------------------------------------------------------
// Copyright (c) 2009 Jounayd Id Salah.
// All rights reserved.
//---------------------------------------------------------------------------------------

